﻿/***************************************************************
*       
* add by OceanHo 2015/8/26 11:59:15
*
****************************************************************/

using oceanho.webapi.factory.httpCore.ReqKernal;
using oceanho.webapi.factory.httpEntity;
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;

namespace oceanho.webapi.factory.httpUtility
{
    /// <summary>
    /// 定义一个工具类。用于管理客户端的请求与连接，ReqCacheDb 的管理
    /// </summary>
    public sealed class ReqCacheDbUtility
    {
        #region -- ReqCacheDbUtility --

        /// <summary>
        /// 校验客户端的请求是否合法
        /// </summary>
        /// <param name="app">System.Web.HttpApplication上下文对象</param>
        /// <param name="reqCache">ReqCache对象，输出参数</param>
        /// <returns></returns>
        internal static bool IsValid(System.Web.HttpApplication app, out ReqCache reqCache)
        {
            bool isCached = false;
            bool isForever = false;
            string key = RequestUtility.GetReqID(app.Request);

            reqCache = AppUtility.Cfg.ReqCacheDb.Get(key, out isCached);
            AppUtility.Cfg.ReqCacheDb.AddReq_Wait_Count(ref reqCache, 1);
            AppUtility.Cfg.ReqCacheDb.AddReq_Seconds_Count(ref reqCache, 1);

            // 解除黑名单（尝试,如果用户属于黑名单IP用户）
            if (reqCache.IsBadIP && IsAllowResetIsBadIP(reqCache))
            {
                AppUtility.Cfg.ReqCacheDb.RemoveBadIP(ref reqCache);
                ComputeNextResetIsBadIPDateAndSetProperty(ref reqCache, ref isForever);
            }

            AppUtility.Cfg.ReqCacheDb.Set(app.Request, key, reqCache, isCached, isForever);
            return AppUtility.Cfg.ReqCacheDb.IsValidIP(reqCache);
        }

        /// <summary>
        /// 减少请求挂起次数
        /// </summary>
        /// <param name="app">System.Web.HttpApplication上下文对象</param>
        internal static void ReduceReqWaitCount(System.Web.HttpApplication app)
        {
            bool isCached = false;
            string key = RequestUtility.GetReqID(app.Request);
            ReqCache reqCache = AppUtility.Cfg.ReqCacheDb.Get(key, out isCached);

            AppUtility.Cfg.ReqCacheDb.AddReq_Wait_Count(ref reqCache, -1);
            AppUtility.Cfg.ReqCacheDb.Set(app.Request, key, reqCache, isCached, false);
        }

        /// <summary>
        /// 校验 ReqCache 是否允许解除IsBadIP标识
        /// </summary>
        /// <param name="reqCache">ReqCache对象</param>
        /// <returns></returns>
        internal static bool IsAllowResetIsBadIP(ReqCache reqCache)
        {
            // 当前时间比解除黑名单时间小，说明已经达到解除黑名单的时间
            return (DateTime.Now.Subtract(reqCache.Req_Allow_Clear_IsBadIP_Date).TotalSeconds >= 0);
        }
        #endregion

        #region -- Private Herper Method --

        /// <summary>
        /// 调整清除ReqCache对象的黑名单清除时间/警告等级等等
        /// </summary>
        /// <param name="reqCache">当前ReqCache对象</param>
        /// <param name="isForever">是否永久移入黑名单IP</param>
        private static void ComputeNextResetIsBadIPDateAndSetProperty(ref ReqCache reqCache, ref bool isForever)
        {
            isForever = true;
            DateTime clearDate = DateTime.MaxValue;
            if (reqCache.Req_Warn_Count < AlgorithmUtility.Int_Fibo_MAX_FOR_APP)
            {
                reqCache.Req_Warn_Lv = AlgorithmUtility.GetFibonacci(reqCache.Req_Warn_Count);

                if (reqCache.Req_Warn_Count >= AppUtility.Cfg.Allow_Warn_Count ||
                    reqCache.Req_Warn_Count >= AlgorithmUtility.Int_Fibo_MAX_FOR_APP)
                {
                    clearDate = DateTime.MaxValue;
                }
                else
                {
                    try
                    {
                        isForever = false;
                        clearDate = DateTime.Now.AddMinutes(reqCache.Req_Warn_Lv * 10);
                    }
                    catch
                    {
                        clearDate = DateTime.MaxValue;
                    }
                }
            }
            reqCache.Req_Allow_Clear_IsBadIP_Date = clearDate;
        }
        #endregion

        #region -- 对外公布API Public Open API --

        /// <summary>
        /// 获取当前HttpRequest的ReqCache,存在缓存返回ReqCache,不存在HttpRequest的缓存返回null
        /// </summary>
        /// <param name="request">HttpRequest对象</param>
        /// <returns></returns>
        public static void RemoveCurrentIsBadIP(HttpRequest request)
        {
            ReqCache reqCache = AppUtility.Cfg.ReqCacheDb.Get(request);
            if (reqCache != null)
            {
                AppUtility.Cfg.ReqCacheDb.RemoveBadIP(ref reqCache, true);
                AppUtility.Cfg.ReqCacheDb.Set(request, RequestUtility.GetReqID(request), reqCache, true, false);
            }
        }

        /// <summary>
        /// 获取当前HttpRequest的ReqCache,存在缓存返回ReqCache,不存在HttpRequest的缓存返回null
        /// </summary>
        /// <param name="request">HttpRequest对象</param>
        /// <returns></returns>
        public static ReqCache GetCurrentReqCache(HttpRequest request)
        {
            return AppUtility.Cfg.ReqCacheDb.Get(request);
        }

        /// <summary>
        /// 获取HttpRequest的ReqID,缓存的HttpRequest转换ReqCache的键
        /// </summary>
        /// <param name="request">HttpRequest</param>
        /// <returns></returns>
        public static string GetCurrentReqID(HttpRequest request)
        {
            return RequestUtility.GetReqID(request);
        }

        /// <summary>
        /// 根据reqID获取获取ReqCache对象
        /// </summary>
        /// <param name="reqID">reqID</param>
        /// <returns></returns>
        public static ReqCache GetReqCache(string reqID)
        {
            return AppUtility.Cfg.ReqCacheDb.GetReqCache(reqID);
        }

        /// <summary>
        /// 根据reqID获取获取ReqCache对象
        /// </summary>
        /// <param name="reqID">reqID</param>
        /// <returns></returns>
        public static bool DeleteReqCache(string reqID)
        {
            return AppUtility.Cfg.ReqCacheDb.Remove(reqID);
        }

        /// <summary>
        /// 移除reqID对于的ReqCache的IsBadIP标识
        /// </summary>
        /// <param name="reqID">reqID</param>
        /// <returns></returns>
        public static bool RemoveReqCacheIsBadIP(string reqID)
        {
            ReqCache reqCache = AppUtility.Cfg.ReqCacheDb.GetReqCache(reqID);
            if (reqCache != null)
            {
                AppUtility.Cfg.ReqCacheDb.RemoveBadIP(ref reqCache, true);
                return AppUtility.Cfg.ReqCacheDb.Set(null, reqID, reqCache, true, false);
            }
            return false;
        }

        /// <summary>
        /// 根据reqID获取获取ReqCache对象
        /// </summary>
        /// <param name="reqID">reqID</param>
        /// <returns></returns>
        public static bool SetReqCacheIsValidIPForever(string reqID)
        {
            ReqCache reqCache = AppUtility.Cfg.ReqCacheDb.GetReqCache(reqID);
            if (reqCache != null)
            {
                AppUtility.Cfg.ReqCacheDb.SetIsValidIPForever(ref reqCache);
                return AppUtility.Cfg.ReqCacheDb.Set(null, reqID, reqCache, true, false);
            }
            return false;
        }

        /// <summary>
        /// 将指定reqID的ReqCache对象永久性加入黑名单
        /// </summary>
        /// <param name="reqID">reqID</param>
        /// <returns></returns>
        public static bool AddToIsBadIPForever(string reqID)
        {
            ReqCache reqCache = AppUtility.Cfg.ReqCacheDb.GetReqCache(reqID);
            if (reqCache != null)
            {
                AppUtility.Cfg.ReqCacheDb.SetBadIPForever(ref reqCache);
                return AppUtility.Cfg.ReqCacheDb.Set(null, reqID, reqCache, true, false);
            }
            return false;
        }
        #endregion
    }
}
